package com.ht.guice.querydsl.dao;

import com.ht.guice.querydsl.entity.Identifiable;
import com.mysema.query.jpa.impl.JPADeleteClause;
import com.mysema.query.jpa.impl.JPAQuery;
import com.mysema.query.jpa.impl.JPAUpdateClause;
import com.mysema.query.types.EntityPath;
import com.mysema.query.types.Predicate;
import com.mysema.query.types.expr.SimpleExpression;

import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import java.io.Serializable;
import java.util.List;

public abstract class AbstractJPADao<T extends Identifiable, P extends Serializable> {

    @Inject
    private Provider<EntityManager> em;

    private JPAQuery query() {
        return new JPAQuery(em.get());
    }

    /**
     * 查询其它实体类
     * @param path
     * @return
     */
    protected JPAQuery from(EntityPath<?> path) {
        return query().from(path);
    }

    /**
     * 查询操作
     * selectFrom().innerJoin(cat.mate, mate).leftJoin(cat.kittens, kitten).list(cat);
     * @return
     */
    protected JPAQuery from() {
        return query().from(getEntityPath());
    }

    /**
     * 根据查询条件进行查询操作:
     * where(customer.firstName.eq("Bob").or(customer.lastName.eq("Wilson")));
     * @param expr
     * @return
     */
    protected JPAQuery where(Predicate ...expr) {
        return from().where(expr);
    }

    /**
     * 按分布进行查询
     * @param expr
     * @param offset
     * @param limit
     * @return
     */
    protected JPAQuery where(long offset, long limit, Predicate ...expr) {
        return from().offset(offset).limit(limit).where(expr);
    }

    /**
     * 查询所有记录
     * @return
     */
    public List<T> findAll() {
        return from().list(getEntityPath());
    }

    /**
     * query.from(customer).where(customer.firstName.eq("Bob").or(customer.lastName.eq("Wilson")));
     * @param expr
     * @return
     */
    protected List<T> findAll(Predicate ...expr) {
        return where(expr).list(getEntityPath());
    }

    protected List<T> findAll(long offset, long limit, Predicate ...expr) {
        return where(expr).offset(offset).limit(limit).list(getEntityPath());
    }

    /**
     * 按给定的条件查询条记录
     * @param expr
     * @return
     */
    protected T findOne(Predicate ...expr) {
        return where(expr).singleResult(getEntityPath());
    }

    /**
     * 根据主键查询对应的实体类
     * @param id
     * @return
     */
    public T fetch(P id) {
        return findOne(getPrimaryKeyExpression().eq(id));
    }

    /**
     * 按给定的条件查询对应的记录是否存在
     * @param expr
     * @return
     */
    protected boolean isExist(Predicate ...expr) {
        return count(expr) > 0;
    }

    /**
     * 数量统计条件查询
     * @param expr
     * @return
     */
    protected long count(Predicate ...expr) {
        return where(expr).count();
    }

    /**
     * 数量统计查询
     * @return
     */
    public long count() {
        return from().count();
    }

    protected JPADeleteClause delete(EntityPath<?> path) {
        return new JPADeleteClause(em.get(), path);
    }

    protected JPADeleteClause delete() {
        return new JPADeleteClause(em.get(), getEntityPath());
    }

    public void delete(T t) {
        em.get().remove(t);
    }

    public void deleteById(P id) {
        deleteWhere(getPrimaryKeyExpression().eq(id));
    }

    protected long deleteWhere(EntityPath<?> path, Predicate ...expr) {
        return new JPADeleteClause(em.get(), path).where(expr).execute();
    }

    protected long deleteWhere(Predicate ...expr) {
        return deleteWhere(getEntityPath(), expr);
    }

    protected void deleteAll(EntityPath<?> path) {
        new JPADeleteClause(em.get(), path).execute();
    }

    public void deleteAll() {
        deleteAll(getEntityPath());
    }

    /**
     * 更新操作
     * @param path
     * @return
     */
    protected JPAUpdateClause update(EntityPath<?> path) {
        return new JPAUpdateClause(em.get(), path);
    }

    /**
     * 更新操作
     * @return
     */
    protected JPAUpdateClause update() {
        return update(getEntityPath());
    }

    /**
     * 按条件进行更新操作
     * @param expr
     * @return
     */
    protected JPAUpdateClause updateWhere(Predicate ...expr) {
        return new JPAUpdateClause(em.get(), getEntityPath()).where(expr);
    }

    public void insertOrUpdate(T t) {
        em.get().persist(t);
    }

    /**
     * 实体类对应的QueryBean, 如QUser
     * @return
     */
    protected abstract EntityPath<T> getEntityPath();

    /**
     * QueryBean与实体类主键对应的查询表示式
     * @return
     */
    protected abstract SimpleExpression<P> getPrimaryKeyExpression();
}